// (C) 2022 Intel Corporation. All rights reserved.
// Your use of Intel Corporation's design tools, logic functions and other 
// software and tools, and its AMPP partner logic functions, and any output 
// files from any of the foregoing (including device programming or simulation 
// files), and any associated documentation or information are expressly subject 
// to the terms and conditions of the Intel Program License Subscription 
// Agreement, Intel FPGA IP License Agreement, or other applicable 
// license agreement, including, without limitation, that your use is for the 
// sole purpose of programming logic devices manufactured by Intel and sold by 
// Intel or its authorized distributors.  Please refer to the applicable 
// agreement for further details.

`timescale 1 ns / 1 ps

module espi_pc_mem_short_fsm
  #(
    parameter HEADER_BYTES = 4,
    parameter DATA_BYTES   = 4
    )
    (
     // Command Decode
     input logic         detect_memrd_short,
     input logic         detect_memwr_short,
     input logic         detect_short_1b,
     input logic         detect_short_2b,
     input logic         detect_short_4b,
    
     // Rx Shifter
     input logic         rx_detect_crc_end,
     input logic         stop_det,
     input [7:0]         header_byte[HEADER_BYTES],
     input [7:0]         data_byte[DATA_BYTES],

     // Error Detection
     input logic         pc_error_condition,
    
     // Avalon Memory-Mapped Memory Master
     output logic        mem_req,
     input logic         mem_gnt,
     output logic [31:0] mem_address,
     output logic        mem_write,
     output logic [31:0] mem_writedata,
     output logic [3:0]  mem_byteenable,
     output logic        mem_read,
     input logic [31:0]  mem_readdata,
     input logic         mem_waitrequest,

     // Needed for the completion
     output logic [1:0]  mem_idx,

     // Tx Shifter
     output logic        pc_mem_data_valid,
     output logic [31:0] pc_mem_data,

     // Globals
     input logic         clk,
     input logic         channel_reset_n
     );

    always @(posedge clk or negedge channel_reset_n) begin
        if (!channel_reset_n) begin
            mem_req           <= 0;
            mem_address       <= 0;
            mem_write         <= 0;
            mem_writedata     <= 0;
            mem_byteenable    <= 0;
            mem_read          <= 0;
            pc_mem_data       <= 0;
            pc_mem_data_valid <= 0;
        end
        else begin
            if (!mem_waitrequest) begin
                mem_write <= 0;
                mem_read  <= 0;
                if (rx_detect_crc_end && !pc_error_condition) begin
                    mem_req <= detect_memrd_short | detect_memwr_short;
                end // if (rx_detect_crc_end && !pc_error_condition)

                if (mem_gnt) begin
                    // The command phase completed successfully, start the operation
                    mem_address   <= {header_byte[0], header_byte[1], header_byte[2],
                                      header_byte[3] & 8'hfc};
                    mem_read      <= detect_memrd_short;
                    mem_write     <= detect_memwr_short;
                    mem_writedata <= 0;
                    if (detect_short_1b) begin
                        mem_writedata[mem_idx*8+:8] <= data_byte[0];
                        mem_byteenable              <= 1'b1 << mem_idx;
                    end
                    if (detect_short_2b) begin
                        mem_writedata[mem_idx*8+:16] <= {data_byte[1], data_byte[0]};
                        mem_byteenable                <= 2'b11 << mem_idx;
                    end
                    if (detect_short_4b) begin
                        mem_writedata  <= {data_byte[3], data_byte[2], data_byte[1], data_byte[0]};
                        mem_byteenable <= 4'b1111;
                    end
                end // if (detect_memrd_short || detect_memwr_short)

                if (mem_read) begin
                    pc_mem_data <= mem_readdata >> (mem_idx*8);
                end

                if (mem_read || mem_write) begin
                    mem_req           <= 0;
                    pc_mem_data_valid <= 1'b1;
                end
            end // if (!mem_waitrequest)

            if (stop_det) begin
                pc_mem_data       <= 0;
                pc_mem_data_valid <= 0;
            end
        end // else: !if(!channel_reset_n)
    end // always @ (posedge clk or negedge channel_reset_n)

    assign mem_idx = header_byte[3][1:0];

endmodule // espi_pc_mem_short_fsm
